<?php

namespace Fendx;

use Fendx\Exception\BizException;
use Fendx\Exception\FendxException;

/**
 * Class Validation
 *
 *
 * $rules 前三个参数参考\Fendx\Request->get/post/json/file()使用方式, 第四个参数参考\Fendx\Validation::make的第二个参数
 * $message 参考\Fendx\Validation::make的第二个参数
 *
 * $rules = [
 *      'field1' => ['post', 'defaultValue', 'string', 'require|url|length:10,255'],
 *      'field2' => ['post', 'defaultValue', 'array', ["same" => ["a", "b"]],
 *      'field3' => ['post', 'defaultValue', 'array', [
 *                                                      '.' => 'require|url|length:10,255',
 *                                                      '.*.name' => 'require|string|length:10,255',
 *                                                      '.*.tags' => ["same" => ["a", "b"],
 *                                                   ]]];
 *
 * @package Fendx
 */
class ValidationRequest
{
    private static $supportMethodMaps = [
        'get' => true,
        'post' => true,
        'json' => true,
        'file' => true,
        'cookie' => true,
        'param' => true,
    ];

    /**
     * 验证Request来的规则
     * @param array $rules = ['post', 'defaultValue', 'string', 'rule'] 前三个参数参考 Request,最后一个参数参考 Validation::make 第二个参数
     *               ['post', 'items', 'array', ['.' => 'rule', '.*.name' => 'rule']]
     */
    public static function make(Request $request, array $rules, array $message = []): array {
        $input = [];
        $checkRules = [];
        foreach ($rules as $fieldName => $rule) {
            $method = self::getMethod($request, $rule[0]);
            $default = $rule[1] ?? '';
            $filter = $rule[2] ?? '';

            // set input
            $input[$fieldName] = $request->$method($fieldName, $default, $filter);

            // 处理要验证的规则
            if (!isset($rule[3])) {
                continue;
            }
            $curRule = $rule[3];

            // 如果是数组并且第一个包含.时，则验证数组对象类型的子元素
            if (is_array($curRule) && false !== strpos($curRule[0], '.')) {
                foreach ($curRule as $subRuleKey => $subRuleVal) {
                    if (0 == strcmp($subRuleKey, '.')) {
                        // 如果子级是.代表要验证根
                        $checkRules[$fieldName] = $subRuleVal;
                    } else {
                        $subFieldName = sprintf("%s%s", $fieldName, $subRuleKey);
                        $checkRules[$subFieldName] = $subRuleVal;
                    }
                }
            } else {
                $checkRules[$fieldName] = $curRule;
            }
        }

        if (!empty($checkRules)) {
            $check = Validation::make($input, $checkRules, $message);
            Validation::checkResult($check);
        }

        return $input;
    }

    private static function getMethod(Request $request, string $method = '') {
        if (!empty($method) && isset(self::$supportMethodMaps[$method])) {
            return $method;
        }
        return $request->getMethod();
    }
}
